/*********************
* Author:Dzlua
* QQ:505544956
* time:2016/09/07
*/
#include "CheckBox.h"
#include "../edui.h"

EDUI_NAMESPACE_BEGIN

typedef std::vector<CheckBox*> GroupMap;
GroupMap g_groupItems;

CheckBox* CheckBox::GetInterface()
{
    CheckBox* checkBox = new CheckBox;
#ifdef EDUI_TEST_NEW_DELETE
    ++m_newdeleteNum;
    Log("[CheckBox] new checkBox : %d", checkBox);
#endif
#ifdef EDUI_USE_LUAPLUS
    LuaMgrPtr->Add("CheckBox", checkBox);
#endif
    return checkBox;
}

void CheckBox::Release()
{
#ifdef EDUI_TEST_NEW_DELETE
    --m_newdeleteNum;
    Log("[CheckBox] delete checkBox : %s, %d", this->GetName(), this);
#endif
#ifdef EDUI_USE_LUAPLUS
    LuaMgrPtr->Remove(this);
#endif
    delete this;
}

CheckBox* CheckBox::ToCheckBox(Control* ctrl)
{
    return dynamic_cast<CheckBox*>(ctrl);
}

CheckBox::CheckBox() : m_bSelected(false), m_group(0), m_bindTableLayoutName(0), m_bindTableLayoutIndex(0)
{
    m_selTextColor.Reset(0, 0, 0, 255);
    m_selHotTextColor.Reset(0, 0, 0, 255);
    m_selPressedTextColor.Reset(0, 0, 0, 255);
    m_selDisabledTextColor.Reset(0, 0, 0, 255);

    m_textAlign = ALIGN_LEFT;

}

CheckBox::~CheckBox()
{
    GroupMap::iterator it;
    for (it = g_groupItems.begin(); it != g_groupItems.end(); ++it){
        if((*it) && ((*it) == this)){
            g_groupItems.erase(it);
            break;
        }
    }

    if (m_group){
        delete m_group;
        m_group = 0;
    }

    if (m_bindTableLayoutName){
        delete m_bindTableLayoutName;
        m_bindTableLayoutName = 0;
    }
}

void _Notify(CheckBox* cbx)
{
    const char* group = cbx->GetGroup();
    if (!group) return;
    IWindow* wnd = cbx->GetWindow();

    for (GroupMap::iterator it = g_groupItems.begin(); it != g_groupItems.end(); ++it){
        if((*it) && ((*it) != cbx)){
            if ((*it)->GetWindow() != wnd) continue;
            const char* tmp = (*it)->GetGroup();
            if (!tmp) continue;
            if (strcmp(tmp, group) != 0) continue;
            (*it)->SetSelect(false, true, false);
        }
    }
}

void CheckBox::SetGroup(const char* group)
{
    if (!group) return;
    if (m_group){
        delete m_group;
    }
    size_t size = strlen(group) + 1;
    m_group = new char[size];
    strcpy(m_group, group);
    m_group[size-1] = 0;
    g_groupItems.push_back(this);
}

const char* CheckBox::GetGroup()
{
    return m_group;
}

bool CheckBox::BindTableLayout(const char* name, int index)
{
    if (!name) return false;
    if (m_bindTableLayoutName){
        delete m_bindTableLayoutName;
    }
    size_t size = strlen(name) + 1;
    m_bindTableLayoutName = new char[size];
    strcpy(m_bindTableLayoutName, name);
    m_bindTableLayoutName[size-1] = 0;
    m_bindTableLayoutIndex = index;
    return true;
}

const char* CheckBox::GetBindTableLayoutName()
{
    return m_bindTableLayoutName;
}

int CheckBox::GetBindTableLayoutIndex()
{
    return m_bindTableLayoutIndex;
}

void CheckBox::DoBindEvent()
{
    if (m_bindTableLayoutName && m_bSelected){
        IWindow* wnd = this->GetWindow();
        TableLayout* tab = TableLayout::ToTableLayout(wnd->FindControl(m_bindTableLayoutName));
        if (tab){
            tab->SetSelected(m_bindTableLayoutIndex);
        }
    }
}

bool CheckBox::IsSelected()
{
    return m_bSelected;
}

void CheckBox::SetSelect(bool bSelected, bool bEvent /*= true*/, bool bNotify /*= true*/)
{
    if (m_bSelected == bSelected) return;
    m_bSelected = bSelected;
    this->Invaldate();
    if (bEvent){
        this->DoEvent(EVENT_CLICK);
    }
    if (m_group && bNotify){
        if (m_bSelected) _Notify(this);
    }
    this->DoBindEvent();
}

bool CheckBox::HandleMsg(Msg* msg)
{
    if (msg->msg == MSG_WND_LEAVE){
        if (m_state != BUTTON_STATE_NORMAL){
            m_state = BUTTON_STATE_NORMAL;
            this->Invaldate();
        }
    }

    if (msg->msg == MSG_MOUSE_MOVE){
        MouseMoveMsg *evt = &msg->motion;
        if (m_rc.IsInRect(evt->x, evt->y)){
            if (evt->state & MOUSE_BUTTON(MOUSE_BUTTON_LEFT)){
                if (m_state !=  BUTTON_STATE_PRESSED){
                    m_state =  BUTTON_STATE_PRESSED;
                    this->Invaldate();
                }
            } else {
                if (m_state !=  BUTTON_STATE_HOT){
                    m_state =  BUTTON_STATE_HOT;
                    this->Invaldate();
                }
            }
            return true;
        } else {
            if (m_state !=  BUTTON_STATE_NORMAL){
                m_state =  BUTTON_STATE_NORMAL;
                this->Invaldate();
            }
        }
    } else if (msg->msg == MSG_MOUSE_BUTTON_DOWN){
        MouseButtonMsg *evt = &msg->button;
        if (m_rc.IsInRect(evt->x, evt->y)){
            if (m_state !=  BUTTON_STATE_PRESSED){
                m_state =  BUTTON_STATE_PRESSED;
                this->Invaldate();
            }
            return true;
        }
    } else if (msg->msg == MSG_MOUSE_BUTTON_UP){
        MouseButtonMsg *evt = &msg->button;
        if (m_rc.IsInRect(evt->x, evt->y)){
            m_bSelected = !m_bSelected;
            if (m_group) m_bSelected = true;

            if (m_state !=  BUTTON_STATE_HOT){
                m_state =  BUTTON_STATE_HOT;
                this->Invaldate();
            }

            this->DoEvent(EVENT_CLICK);
            if (m_bSelected) _Notify(this);
            this->DoBindEvent();

            return true;
        } else {
            if (m_state !=  BUTTON_STATE_NORMAL){
                m_state =  BUTTON_STATE_NORMAL;
                this->Invaldate();
            }
        }
    }

    if (msg->msg == MSG_KEY_DOWN){
        KeyboardMsg* evt = &msg->key;
        if (evt->key == KEY_RETURN){
            m_bSelected = !m_bSelected;
            if (m_group) m_bSelected = true;
            this->Invaldate();

            this->DoEvent(EVENT_KEY_ENTER);
            if (m_bSelected) _Notify(this);
            this->DoBindEvent();
        }
    }

    return Control::HandleMsg(msg);
}

void CheckBox::RenderStatusImages(IRender* render, const Rect* rc)
{
    if (!m_bEnabled){
        m_state = BUTTON_STATE_DISABLED;
    }
    
    if (m_bSelected){
        if (m_state == BUTTON_STATE_NORMAL){
            this->DrawImage(render, &m_selNormalImage);
        } else if (m_state == BUTTON_STATE_HOT){
            this->DrawImage(render, &m_selHotImage);
        } else if (m_state == BUTTON_STATE_PRESSED){
            this->DrawImage(render, &m_selPressedImage);
        } else if (m_state == BUTTON_STATE_DISABLED){
            this->DrawImage(render, &m_selDisabledImage);
        }
    } else {
        Button::RenderStatusImages(render, rc);
    }
}

void CheckBox::RenderText(IRender* render, const Rect* renderrc)
{
    if (!m_bSelected){
        Button::RenderText(render, renderrc);
        return;
    }

    if (!m_bEnabled){
        m_state = BUTTON_STATE_DISABLED;
    }
    
    if (m_text.IsEmpty()) return;

    //get text
    const char* text = this->GetTranslateText();
    if (!text) return;

    //get font
    IFont* font = this->GetFont();
    if (!font) return;

    //render
    Size sz = font->GetSizeUTF8(text);
    Rect rc = this->GetTextAlignRect(&sz);

    switch (m_state){
    case BUTTON_STATE_NORMAL :
        render->DrawText(text, &rc, font, &m_selTextColor);
        break;
    case BUTTON_STATE_HOT :
        render->DrawText(text, &rc, font, &m_selHotTextColor);
        break;
    case BUTTON_STATE_PRESSED :
        rc.x += m_ptPressedOffset.x;
        rc.y += m_ptPressedOffset.y;

        render->DrawText(text, &rc, font, &m_selPressedTextColor);
        break;
    case BUTTON_STATE_DISABLED :
        render->DrawText(text, &rc, font, &m_selDisabledTextColor);
        break;
    }
}

Color* CheckBox::GetDestColor(const char* value)
{
    if (0 == strcmp(value, "seltext")){
        return &m_selTextColor;
    } else if (0 == strcmp(value, "selhottext")){
        return &m_selHotTextColor;
    } else if (0 == strcmp(value, "selpressedtext")){
        return &m_selPressedTextColor;
    } else if (0 == strcmp(value, "seldisabledtext")){
        return &m_selDisabledTextColor;
    }
    return Button::GetDestColor(value);
}

ImageData* CheckBox::GetDestImageData(const char* value)
{
    if (0 == strcmp(value, "selnormal")){
        return &m_selNormalImage;
    } else if (0 == strcmp(value, "selhot")){
        return &m_selHotImage;
    } else if (0 == strcmp(value, "selpressed")){
        return &m_selPressedImage;
    } else if (0 == strcmp(value, "seldisabled")){
        return &m_selDisabledImage;
    }
    return Button::GetDestImageData(value);
}

void CheckBox::SetAttribute(const char* name, const char* value)
{
    if (0 == strcmp(name, "selected")){
        m_bSelected = ParserBool(value, false);
    } else if (0 == strcmp(name, "group")){
        this->SetGroup(value);
    } else if (0 == strcmp(name, "tablelayout")){
        int idx = 0;
        String tmpname;
        Parser par(value);
        for (Parser::Attribute* it = par.First(); it; it = par.Next()){
            if (0 == strcmp(it->Name(), "name")){
                tmpname = it->Value();
            } else if (0 == strcmp(it->Name(), "idx")){
                ParserInt(it->Value(), &idx, 0);
            }
        }
        this->BindTableLayout(tmpname.GetString(), idx);
    } else {
        Button::SetAttribute(name, value);
    }
}

void CheckBox::DoEvent(EventType type, void* data1, void* data2)
{
    switch (type){
        case EVENT_CLICK :     this->evt.selected.emit(this); break;
        case EVENT_KEY_ENTER : this->evt.selected.emit(this); break;
    }
#ifdef EDUI_USE_LUAPLUS
    switch (type){
        case EVENT_CLICK : LuaMgrPtr->DoEvent(this, "selected"); break;
        case EVENT_KEY_ENTER : LuaMgrPtr->DoEvent(this, "selected"); break;
    }
#endif
}

EDUI_NAMESPACE_END
